#include "weight.h"
#include "pick.h"
#include <glib.h>
#include <string.h>

// warts!
extern int min_size_pen;
extern int max_size_pen;
extern int min_olap_pen;
extern int max_olap_pen;

static gint compare(const gulong** wgts1, const gulong** wgts2);

EdgeWeight*
weight_new(void)
{
    return g_new0(EdgeWeight, 1);
}

EdgeWeight*
weight_max(void)
{
    EdgeWeight* result;
    result = weight_new();
    weight_make_max(result);
    return result;
}

void
weight_make_max(EdgeWeight* weight)
{
    g_return_if_fail(weight != NULL);

    weight->bss = -1;
    weight->fp = -1;
}

void
weight_make_min(EdgeWeight* weight)
{
    g_return_if_fail(weight != NULL);

    weight->bss = 0;
    weight->fp = 0;
}

void
weight_init(EdgeWeight* weight, glong olap, enum pairTypes pair_type,
            gboolean prefer_large, guint sizeL, guint sizeR)
{
    gulong overlap;
    gulong *acc;

    g_return_if_fail(weight != NULL);

    weight_make_min(weight);
    switch (pair_type) {
    case BSS_DRAFT:
        acc = &weight->fp;
		overlap = olap;
        break;

    case FINGERPRINT:
        acc = &weight->fp;
        overlap = olap;
        if (overlap < min_olap_pen)
            min_olap_pen = overlap;
        if (overlap > max_olap_pen)
            max_olap_pen = overlap;

        if (prefer_large) {
            int size_penalty;
            size_penalty = get_size_penalty(sizeL, sizeR);
            if (size_penalty < min_size_pen)
                min_size_pen = size_penalty;
            if (size_penalty > max_size_pen)
                max_size_pen = size_penalty;
            overlap += size_penalty;
        }
        break;

    case MANDATORY:
        acc = &weight->fp;
		overlap = olap;
        if (overlap < min_olap_pen)
            min_olap_pen = overlap;
        if (overlap > max_olap_pen)
            max_olap_pen = overlap;
        break;

    default:
        g_assert_not_reached();
        break;
    }

    *acc = overlap;
}

void
weight_copy(EdgeWeight* dst, const EdgeWeight* src)
{
    g_return_if_fail(dst != NULL);
    g_return_if_fail(src != NULL);

    memcpy(dst, src, sizeof(EdgeWeight));
}

void
weight_add(EdgeWeight* acc, const EdgeWeight* addend)
{
    g_return_if_fail(acc != NULL);
    g_return_if_fail(addend != NULL);

    acc->bss += addend->bss;

    acc->fp += addend->fp;

}

gint
weight_compare(const EdgeWeight* weight1, const EdgeWeight* weight2)
{
	if (weight1->fp < weight2->fp) return -1;
	if (weight1->fp > weight2->fp) return 1;
	return 0;

    const gulong* w1[] =
        {&(weight1->fp),
         &(weight1->bss),
         NULL
        };
    const gulong* w2[] =
        {&(weight2->fp),
         &(weight2->bss),
         NULL
        };

    return compare(w1, w2);
}

void
weight_destroy(EdgeWeight** weight)
{
    g_return_if_fail(weight != NULL);
    g_return_if_fail(*weight != NULL);

    g_free(*weight);
    *weight = NULL;
}

static gint
compare(const gulong** wgts1, const gulong** wgts2)
{
    gint result = 0;

    while (result == 0 && *wgts1 != NULL && *wgts2 != NULL) {
        if (**wgts1 < **wgts2)
            result = -1;
        else if (**wgts1 > **wgts2)
            result = 1;
        ++wgts1;
        ++wgts2;
    }
    return result;
}
